package ast

import (
	"fmt"
	"sync"

	"gitee.com/u-language/u-language/ucom/enum"
	"gitee.com/u-language/u-language/ucom/errcode"
	"gitee.com/u-language/u-language/ucom/lex"
)

// found 是find的过去式
const opexpr_found_assign = "opexpr_found_assign"

const call_parser_fail = "call_parser_fail"

const op_bug = "op_bug"

const parserobj_nil = "parserobj_nil"

type stack struct {
	opStack    []enum.OPSymbol
	valueStack []Expr
	FuncInfo   *FuncInfo
	opIndex    int
	valueIndex int
	err        errcode.ErrCode
	inAutoFree bool
	BeforeOp   bool //Before operator
}

const (
	equal        int8 = 0  //等于
	less_than    int8 = -1 //小于
	greater_than int8 = 1  //大于
)

// 操作的优先级枚举值，值越小，优先级越低
const (
	logicOr            = iota + 1 // ||
	logicAND                      // &&
	or                            // |
	xor                           // ^
	and                           // and
	judgeEqual                    // == !=
	compareSize                   // < >
	addAndSub                     // + -
	mulAndDlvAndRemain            // * / %
	paren                         // parentheses (
)

var stackpool = sync.Pool{
	New: func() interface{} {
		return &stack{
			valueIndex: -1,
			opIndex:    -1,
			valueStack: make([]Expr, 0, 2),
			opStack:    make([]enum.OPSymbol, 0, 1),
		}
	},
}

func newstack(FuncInfo *FuncInfo, inAutoFree bool) (s *stack) {
	s = stackpool.Get().(*stack)
	s.FuncInfo, s.inAutoFree = FuncInfo, inAutoFree
	return
}

// PushOp 将一个运算符放入运算符栈栈顶
func (s *stack) PushOp(op enum.OPSymbol, t *Tree, line *lex.Line) {
	if s.BeforeOp {
		s.Panic(t, line, nil, errcode.AdjacentOp)
	}
	s.opIndex++
	s.opStack = append(s.opStack[0:s.opIndex], op)
	s.BeforeOp = true
}

// PushValue 将一个值放入值栈栈顶
func (s *stack) PushValue(v Expr) {
	s.valueIndex++
	s.valueStack = append(s.valueStack[0:s.valueIndex], v)
	s.BeforeOp = false
}

// PopOp 将一个运算符从运算符栈栈顶弹出
func (s *stack) PopOp() (op enum.OPSymbol) {
	op = s.opStack[s.opIndex]
	s.opIndex--
	return
}

// PopValue 将一个值从值栈栈顶弹出
func (s *stack) PopValue() (n Expr) {
	n = s.valueStack[s.valueIndex]
	s.valueIndex--
	return
}

// OpStackEmpty 判断运算符栈是否为空
func (s *stack) OpStackEmpty() bool {
	return s.opIndex == -1
}

// CmpOp 比较运算符与栈顶运算符的优先级
//
// 对于不能处理的，将panic
func (s *stack) CmpOp(op enum.OPSymbol) int8 {
	op2 := s.opStack[s.opIndex]
	if op2 == enum.LPARENOP || op2 == enum.CommaOP {
		return greater_than
	}
	openum := opPriorityEnum(op)
	op2enum := opPriorityEnum(op2)
	if openum > op2enum {
		return greater_than
	} else if openum < op2enum {
		return less_than
	}
	if openum == op2enum { //如果优先级相同，右边的比左边小
		return less_than
	}
	return 0
}

// opPriorityEnum 返回操作的优先级枚举值
func opPriorityEnum(op enum.OPSymbol) int8 {
	switch op {
	case enum.NoEqualOP, enum.EqualOP:
		return judgeEqual
	case enum.LessOP, enum.GreaterOP:
		return compareSize
	case enum.ADDOP, enum.SUBOP:
		return addAndSub
	case enum.MULOP, enum.DIVOP, enum.RemainOP:
		return mulAndDlvAndRemain
	case enum.AndOP:
		return and
	case enum.OrOP:
		return or
	case enum.XorOp:
		return xor
	case enum.LogicAndOP:
		return logicAND
	case enum.LogicOrOP:
		return logicOr
	case enum.LPARENOP:
		return paren
	default:
		panic(fmt.Errorf("不能处理的 op:%+v", op))
	}
}

// AutoPush 自动将一个 [lex.Token] 推入值栈或运算符栈
func (s *stack) AutoPush(t *Tree, tk *lex.Token, line *lex.Line) {
	switch tk.TYPE {
	case lex.ADD: //是加号
		s.AutoCmpAndPush(enum.ADDOP, t, line)
	case lex.SUB: //是减号
		s.AutoCmpAndPush(enum.SUBOP, t, line)
	case lex.MUL: //是乘号
		s.AutoCmpAndPush(enum.MULOP, t, line)
	case lex.DIV: //是除号
		s.AutoCmpAndPush(enum.DIVOP, t, line)
	case lex.Equal: //比较是否相等
		s.AutoCmpAndPush(enum.EqualOP, t, line)
	case lex.NoEqual: //比较是否不相等
		s.AutoCmpAndPush(enum.NoEqualOP, t, line)
	case lex.Less: //比较是否小于
		s.AutoCmpAndPush(enum.LessOP, t, line)
	case lex.Greater: //比较是否大于
		s.AutoCmpAndPush(enum.GreaterOP, t, line)
	case lex.Remain: //是取余数
		s.AutoCmpAndPush(enum.RemainOP, t, line)
	case lex.AND: //是位与运算
		s.AutoCmpAndPush(enum.AndOP, t, line)
	case lex.Or: //是位或运算
		s.AutoCmpAndPush(enum.OrOP, t, line)
	case lex.Xor: //是异或运算
		s.AutoCmpAndPush(enum.XorOp, t, line)
	case lex.LogicAND: //是逻辑与运算
		s.AutoCmpAndPush(enum.LogicAndOP, t, line)
	case lex.LogicOr: //是逻辑或运算
		s.AutoCmpAndPush(enum.LogicOrOP, t, line)
	case lex.NUMBER, lex.NAME, lex.FLOAT, lex.String, lex.TRUE, lex.FALSE, lex.LEA, lex.Deref, lex.Nil: //可能是值
		obj := parserObject(t, tk, line, s.FuncInfo)
		if obj == nil {
			panic(parserobj_nil)
		}
		s.PushValue(obj)
	case lex.ASSIGN: //有赋值时不可能产生运算表达式
		s.Panic(t, line, nil, errcode.AFIE)
		panic(opexpr_found_assign)
	case lex.LPAREN: //如果是左小括号
		s.PushOp(enum.LPARENOP, t, line)
	case lex.RPAREN: //如果是右小括号
		for !s.OpStackEmpty() {
			op := s.PopOp() //弹出一个运算符
			if op == enum.LPARENOP || op == enum.CommaOP {
				break
			}
			src2 := s.PopValue()              //弹出右边操作数
			src1 := s.PopValue()              //弹出左边操作数
			expr := NewOpExpr(op, src1, src2) //将运算后的值压入值栈栈顶
			expr.Inparen = true
			s.PushValue(expr)
		}
	case lex.OnlyDeref: //如果是解引用
		s.AutoCmpAndPush(enum.DerefOP, t, line)
	case lex.Comma: //如果是逗号
		s.PushOp(enum.CommaOP, t, line)
	case lex.MoreThanJustTokensWithBrackts: //如果是不止中括号的token,视为索引表达式
		l := *tk.PtrMoreThanJustTokensWithBracktsS().Ptr
		i := parserIndexExpr(t, line, &l[0], &l[1], s.FuncInfo)
		if i == nil {
			s.Panic(t, line, nil, errcode.OPbug)
			panic(op_bug)
		}
		s.PushValue(i)
	default:
		err := token_typ_err[tk.TYPE]
		if err != errcode.NoErr {
			s.Panic(t, line, nil, err)
		} else {
			s.Panic(t, line, nil, errcode.OPbug)
		}
		panic(op_bug)
	}
}

func (s *stack) Panic(t *Tree, line *lex.Line, msg errcode.Msg, err ...errcode.ErrCode) {
	if s.err != errcode.NoErr {
		err_slice := make([]errcode.ErrCode, len(err)+1)
		err_slice[0] = s.err
		for i, v := range err {
			err_slice[i+1] = v
		}
		t.Panic(line, nil, err_slice...)
	} else {
		t.Panic(line, nil, err...)
	}
}

// AutoCmpAndPush 自动以合适的方式将运算符压入栈中
func (s *stack) AutoCmpAndPush(op enum.OPSymbol, t *Tree, line *lex.Line) {
	if s.OpStackEmpty() { //空栈
		s.PushOp(op, t, line) //直接压入栈中
	} else {
		switch s.CmpOp(op) {
		case less_than:
			s.AutoPopAndCmp(op)
			s.PushOp(op, t, line)
		case greater_than:
			s.PushOp(op, t, line)
		}
	}
}

// AutoPopAndCmp 自动将运算符栈和值栈做出栈操作，直到运算符优先级大于运算符栈栈顶运算符优先级，或运算符栈为空
func (s *stack) AutoPopAndCmp(op enum.OPSymbol) {
	for !s.OpStackEmpty() && s.CmpOp(op) == less_than && len(s.valueStack) >= 2 {
		op := s.PopOp() //弹出一个运算符
		if op == enum.DerefOP {
			s.PushValue(&Dereference{Value: s.PopValue()})
			continue
		}
		src2 := s.PopValue()                   //弹出右边操作数
		src1 := s.PopValue()                   //弹出左边操作数
		s.PushValue(NewOpExpr(op, src1, src2)) //将运算后的值压入值栈栈顶
	}
}

// AutoPop 自动将当前的运算符和值转换为一个表达式
func (s *stack) AutoPop(t *Tree, line *lex.Line) (n Expr) {
	for !s.OpStackEmpty() && s.valueIndex >= 1 { //还有运算符及至少两个值
		op := s.PopOp()         //弹出一个运算符
		if op == enum.CommaOP { //如果出现意外的逗号
			s.Panic(t, line, nil, errcode.UnexpectedComma)
			panic(op_bug)
		}
		src2 := s.PopValue()                   //弹出右边操作数
		src1 := s.PopValue()                   //弹出左边操作数
		s.PushValue(NewOpExpr(op, src1, src2)) //将运算后的值压入值栈栈顶
	}
	if s.valueIndex != 0 { //不是只有结果一个
		return nil
	}
	return s.PopValue() //弹出转换后的表达式
}

// AutoExpr 自动将一个赋值文本转换为赋值节点
func (s *stack) AutoExpr(t *Tree, line *lex.Line) (ret *ASSIGNNode) {
	var dest Expr = parserObject(t, &line.Value[0], line, s.FuncInfo) //解析目的操作数
	llen := len(line.Value)
	defer func() {
		if err := recover(); err != nil {
			if predefined_error(err) { //出现预定义的错误
				ret = nil
				return
			}
			panic(err)
		}
	}()
	for i := 2; i < llen; i++ {
		if s.isCall(t, line, &i) {
			continue
		}
		s.AutoPush(t, &line.Value[i], line) //将源操作数和运算符入栈
	}
	node := s.AutoPop(t, line) //获取表达式
	if node == nil {           //没有成功转换为一个表达式
		s.Panic(t, line, nil, errcode.OPbug)
		return nil
	}
	ret = NewASSIGNNode(dest, node) //创建赋值节点
	return ret
}

// AutoExprNode 自动将一个表达式转换为表达式节点
func (s *stack) AutoExprNode(t *Tree, line *lex.Line) (ret Expr) {
	llen := len(line.Value)
	defer func() {
		if err := recover(); err != nil {
			if predefined_error(err) { //出现预定义的错误
				ret = nil
				return
			}
			panic(err)
		}
	}()
	for i := 0; i < llen; i++ {
		if s.isCall(t, line, &i) {
			continue
		}
		s.AutoPush(t, &line.Value[i], line) //将源操作数和运算符入栈
	}
	ret1 := s.AutoPop(t, line)                                //获取表达式
	if ret1 == nil && s.valueIndex != -1 && s.opIndex != -1 { //非空行，没有成功转换为一个表达式
		s.Panic(t, line, nil, errcode.OPbug)
	}
	return ret1
}

// AutoExprNode 自动将一个参数列表为表达式节点
func (s *stack) AutoParameList(t *Tree, line *lex.Line) (ret []Expr) {
	llen := len(line.Value)
	defer func() {
		if err := recover(); err != nil {
			if predefined_error(err) { //出现预定义的错误
				return
			}
			panic(err)
		}
	}()
	// 对于 name([ParameList]) 是无参函数调用
	if llen == 3 {
		return nil
	}
	// 对于 name(ParameList) 从词法分析结果偏移量2开始处理,因为这个函数从parserCall调用，最后面肯定是)
	for i := 2; i < llen-1; i++ {
		if s.isCall(t, line, &i) {
			continue
		}
		s.AutoPush(t, &line.Value[i], line) //将源操作数和运算符入栈
	}
	for !s.OpStackEmpty() && s.valueIndex >= 1 { //还有运算符及至少两个值
		op := s.PopOp()         //弹出一个运算符
		if op == enum.CommaOP { //跳过逗号
			continue
		}
		src2 := s.PopValue()                   //弹出右边操作数
		src1 := s.PopValue()                   //弹出左边操作数
		s.PushValue(NewOpExpr(op, src1, src2)) //将运算后的值压入值栈栈顶
	}
	ret = s.valueStack
	s.valueStack = nil
	return ret
}

// isCall 判断是否存在函数调用并自动处理
func (s *stack) isCall(t *Tree, line *lex.Line, i *int) bool {
	llen := len(line.Value)
	match := leftRightMatch{}
	if *i+1 != llen && line.Value[*i+1].TYPE == lex.LPAREN { //有左小括号，视为函数调用
		old, ok := *i, false
	forcheck:
		for *i+1 < llen {
			*i++
			switch line.Value[*i].TYPE {
			case lex.RPAREN: //发现右小括号
				match.rightNum++
				if match.Ok() { //左右小括号数量匹配，视为完整的函数调用
					nline := lex.NewLine(line.Linenum, line.Value[old:*i+1])
					ret := parserCall(t, &nline, s.inAutoFree, s.FuncInfo)
					if ret == nil { //如果解析函数调用失败
						panic(call_parser_fail)
					}
					s.PushValue(ret)
					ok = true
					break forcheck
				}
			case lex.LPAREN: //发现左小括号
				match.leftNum++
			}
		}
		if !ok { //如果没有右小括号
			if s.err != errcode.NoErr {
				t.Panic(line, nil, s.err, errcode.CallErr, errcode.EmptyRPAREN)
			} else {
				t.Panic(line, nil, errcode.CallErr, errcode.EmptyRPAREN)
			}
			panic(call_parser_fail)
		}
		return true
	}
	return false
}

func (s *stack) Close() {
	s.opIndex, s.valueIndex, s.opStack, s.err, s.BeforeOp = -1, -1, s.opStack[0:0], errcode.NoErr, false
	stackpool.Put(s)
}

func predefined_error(err interface{}) bool {
	if str, ok := err.(string); ok && (str == opexpr_found_assign || str == call_parser_fail || str == op_bug || str == parserobj_nil) { //出现预定义的错误
		return true
	}
	return false
}
